package com.seadragon.app.dms.controller;

import static com.seadragon.app.dms.model.DmsConstants.SESSION_SCOPED_ORDER;
import static com.seadragon.app.dms.model.DmsConstants.SESSION_SCOPED_USER;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;

import com.seadragon.app.dms.model.Address;
import com.seadragon.app.dms.model.CreditCard;
import com.seadragon.app.dms.model.Customer;
import com.seadragon.app.dms.model.Order;
import com.seadragon.app.dms.model.OrderStatus;
import com.seadragon.app.dms.model.Payment;
import com.seadragon.app.dms.model.ScheduledPickupDate;
import com.seadragon.app.dms.model.ShippingPackage;
import com.seadragon.app.dms.service.CustomerService;
import com.seadragon.app.dms.service.OrderService;
import com.seadragon.app.dms.service.PricingService;

@SessionAttributes(SESSION_SCOPED_ORDER)
@Controller
public class OrderProcessController {

	@Autowired
	private PricingService pricingService;
	@Autowired
	private CustomerService customerService;
	@Autowired
	private OrderService orderService;

	public PricingService getPricingService() {
		return pricingService;
	}
	public void setPricingService(PricingService pricingService) {
		this.pricingService = pricingService;
	}

	@RequestMapping("/process-an-order.html")
	public String showProcessAnOrder(Model model) {
		model.addAttribute("selectedMenuItem", "home");
		return "welcome";
	}

	@RequestMapping("/place-an-order.html")
	public String showPlaceAnOrder(HttpServletRequest request, Model model) {

		// add dummy data for auto populating form, easy for test/debug, should
		// be removed eventually
		if (request.getSession().getAttribute(SESSION_SCOPED_ORDER) == null) {
			model.addAttribute("order", DummyData.getDummyOrder());
		} else {
			model.addAttribute("order", request.getSession().getAttribute(SESSION_SCOPED_ORDER));
		}
		model.addAttribute("selectedMenuItem", "place-an-order");
		return "placeAnOrder";
	}

	@RequestMapping(value = "/set-order-payment.html", method = RequestMethod.POST)
	public String setPayment(@ModelAttribute("order") @Valid Order order,
			BindingResult result, SessionStatus status,
			HttpServletRequest request, Model model) {
		order.setPrice(this.pricingService.calculate(order));

		// manually add packages into packagesSet and order
		Set<ShippingPackage> packageSet = new HashSet<ShippingPackage>();
		ShippingPackage[] packages = null;
		String[] weightArray = request.getParameterValues("packages.weight");
		String[] lengthArray = request.getParameterValues("packages.length");
		String[] widthArray = request.getParameterValues("packages.width");
		String[] heightArray = request.getParameterValues("packages.height");
		String[] valueArray = request.getParameterValues("packages.value");
		if (weightArray != null && weightArray.length > 0
				&& lengthArray != null && lengthArray.length > 0
				&& widthArray != null && widthArray.length > 0
				&& heightArray != null && heightArray.length > 0
				&& weightArray.length == lengthArray.length
				&& weightArray.length == widthArray.length
				&& weightArray.length == valueArray.length
				&& weightArray.length == heightArray.length) {
			packages = new ShippingPackage[weightArray.length];
			for (int i = 0; i < weightArray.length; i++) {
				packages[i] = new ShippingPackage();
				packages[i].setWeight(new Integer(weightArray[i]).intValue());
				packages[i].setLength(new Integer(lengthArray[i]).intValue());
				packages[i].setWidth(new Integer(widthArray[i]).intValue());
				packages[i].setHeight(new Integer(heightArray[i]).intValue());
				packages[i].setValue(new Integer(valueArray[i]).intValue());
				packageSet.add(packages[i]);
			}
		}
		order.setPackages(packageSet);
		// manually add scheduledPickupDate into Set and order
		SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm");
		String pickupDate = request
				.getParameter("schedulePickupDateList.pickupDateScheduled");
		Set<ScheduledPickupDate> schedulePickupDateList = new HashSet<ScheduledPickupDate>();
		ScheduledPickupDate pDate = new ScheduledPickupDate();
		if (StringUtils.isNotEmpty(pickupDate)) {
			try {
				pDate.setPickupDateScheduled(sdf.parse(pickupDate));
				pDate.setValid(true);
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			schedulePickupDateList.add(pDate);
		}
		order.setSchedulePickupDateList(schedulePickupDateList);
		Customer customer = (Customer) request.getSession().getAttribute(
				SESSION_SCOPED_USER);
		model.addAttribute("creditCardList", customer.getCreditCards());
		order.setCustomer(customer);
		request.getSession().setAttribute(SESSION_SCOPED_ORDER, order);
		return "setOrderPayment";
	}

	@RequestMapping(value = "/set-order-payment.html", method = RequestMethod.GET)
	public String setPayment(HttpServletRequest request, Model model,
			SessionStatus status) {
		Order order = (Order) request.getSession().getAttribute(
				SESSION_SCOPED_ORDER);
		if (order != null) {
			return setPayment(order, null, status, request, model);
		} else {
			return showPlaceAnOrder(request, model);
		}
	}

	// //update customer credit card list
	// @ModelAttribute("creditCards")
	// public Customer populateCreditCardList(HttpServletRequest
	// request,ArrayList<CreditCard> creditCards) {
	// Customer customer
	// =(Customer)request.getSession().getAttribute(SESSION_SCOPED_USER);
	// //todo:validate each credit card
	// if (creditCards!=null&&creditCards.size()>0)
	// customer.setCreditCards(creditCards);
	// return customer;
	// }

	//a credit card id will be passed in as a payment credit card Id
	@RequestMapping(value = "/order-review.html", method = RequestMethod.POST)
	public String showOrderReview(HttpServletRequest request, Model model,@RequestParam("cardId") Long cardId,@RequestParam("amount") float amount) {
		Order order = (Order)request.getSession().getAttribute(SESSION_SCOPED_ORDER);
		Customer customer = (Customer)request.getSession().getAttribute(SESSION_SCOPED_USER);
		Set<Payment> payments = new HashSet<Payment>();
		Payment payment = new Payment();
		payment.setAmount(amount);
		payment.setCreditCard(customer.getCreditCardById(cardId));
		payment.setOrder(order);
		payment.setDateCreated(new Date());
		payments.add(payment);
		order.setPayments(payments);
		
		model.addAttribute("selectedMenuItem", "order-review");
		return "orderReview";
	}

	@RequestMapping("/order-review.html")
	public String showOrderReview(Model model) {
		model.addAttribute("order", DummyData.getDummyOrder());
		model.addAttribute("selectedMenuItem", "order-review");
		return "orderReview";
	}

	@RequestMapping("/order-confirmation.html")
	public String showOrderConfirmation(Model model) {
		return "redirect:/place-an-order.html";
	}
	
	@RequestMapping(value="/order-confirmation.html",method=RequestMethod.POST)
	public String showOrderConfirmation(HttpServletRequest request, Model model) {
		Order order = (Order)request.getSession().getAttribute(SESSION_SCOPED_ORDER);
		if (order != null){
			Set<OrderStatus> statuses = new HashSet<OrderStatus>();
			OrderStatus orderStatus = new OrderStatus();
			orderStatus.setDateCreated(new Date());
			orderStatus.setOrder(order);
			orderStatus.setStatus("Confirmed");
			statuses.add(orderStatus);
			order.setStatuses(statuses);
			orderService.save(order);
		}
		//remove the order from session:
		model.addAttribute("order",order);
		request.getSession().removeAttribute(SESSION_SCOPED_ORDER);
		model.addAttribute("selectedMenuItem", "order-confirmation");
		return "orderConfirmation";
	}

	@RequestMapping("/order-status-tracking.html")
	public String showOrderStatusTracking(Model model) {
		model.addAttribute("selectedMenuItem", "order-status-tracking");
		return "orderStatusTracking";
	}

	@RequestMapping("/order-history.html")
	public String showOrderHistory(Model model) {
		model.addAttribute("selectedMenuItem", "order-history");
		return "orderHistory";
	}

	// validate and add credit card
	@RequestMapping(value = "/add-creditcard.json", method = RequestMethod.POST)
	public @ResponseBody
	Map<String, Object> validateAndAddCreditCard(
			@ModelAttribute("creditCard") @Valid CreditCard creditCard,
			BindingResult result, HttpServletRequest request) {
		Map<String, Object> infoMsgs = new HashMap<String, Object>();
		// dummy error msg:
		// result.addError(new ObjectError("accountNumber",
		// "Invalid Account Number!"));
		// result.addError(new ObjectError("expireationDate",
		// "Credit card is expired!"));
		List<String> errList = new ArrayList<String>();
		if (result.hasErrors()) {
			for (ObjectError error : result.getAllErrors()) {
				errList.add(error.getDefaultMessage());
			}
			infoMsgs.put("errMsgs", errList);
		} else {
			Customer customer = (Customer) request.getSession().getAttribute(
					SESSION_SCOPED_USER);
			if (customer != null && customer.getCreditCards() != null) {
				if (customer.addCreditCard(creditCard)) {
					//if billingAddress is empty, set customer address as billingAddress
					if (creditCard.getBillingAddress()==null||StringUtils.isEmpty(creditCard.getBillingAddress().getAddressLine1())){
						Address billingAddress = new Address();
						billingAddress.setAddressLine1(customer.getResidentAddress().getAddressLine1());
						billingAddress.setAddressLine2(customer.getResidentAddress().getAddressLine2());
						billingAddress.setCity(customer.getResidentAddress().getCity());
						billingAddress.setState(customer.getResidentAddress().getState());
						billingAddress.setZip(customer.getResidentAddress().getZip());
						creditCard.setBillingAddress(billingAddress);
//						creditCard.setBillingAddress(customer.getResidentAddress());
					}
					customer=customerService.update(customer);
					request.getSession().setAttribute(SESSION_SCOPED_USER, customer);
					//loop over the credit card Set to get the id for newly added credit card
					for (CreditCard cc : customer.getCreditCards()) {
						if (cc.getAccountNumber().equals(creditCard.getAccountNumber())){
							infoMsgs.put("creditCardId", cc.getId());
						}
					}
				} else {
					errList.add("Duplicated credit card");
					infoMsgs.put("errMsgs", errList);
				}
			}
		}
		return infoMsgs;
	}

	// remove credit card
	@RequestMapping(value = "/creditCard/{creditCardId}/remove.json", method = RequestMethod.POST)
	public @ResponseBody boolean removeCreditCard(@PathVariable String creditCardId,
			HttpServletRequest request, Model model) {
		boolean remove = false;
		Customer customer = (Customer) request.getSession().getAttribute(
				SESSION_SCOPED_USER);
		if (customer != null && customer.getCreditCards() != null) {
			for (CreditCard cc : customer.getCreditCards()) {
				if (cc.getId() == new Long(creditCardId)) {
					remove = customer.getCreditCards().remove(cc);
					customerService.update(customer);
					break;
				}
			}
		}
		return remove;
	}
}
